package TAIC.feature;
import java.util.*;
import java.io.*; 

public class AssignSalient {
	int totalCenters = 0 ;
	int DIM = 0 ;
	double 	center [][] = null ;
	int [][] salientMap;
	double ratioH, ratioW ;
	
	static public void main ( String str []) throws Exception {
		if ( str.length < 4 ) {
			System.out.println ( "please input:") ;
			System.out.println ( "all, configFile, codeBook and outputfile" ) ;
			System.out.println ( "or one, dataFolder, codeBook and outputfile" ) ;
			return ;
		}
		
		if ( str[0].equals( "all") ) 
			( new AssignSalient ( str[ 2 ])).generateAllDataSets( str[ 1 ], str [ 3 ] ) ;
		else if ( str[ 0 ].equals("one")) {
			String imageCorpus = str[ 1 ] + "\\ImageCorpus.txt" ; 
			String dstPath = str[ 1 ] + str [ 3 ] ;
			( new AssignSalient ( str[ 2 ])).generateOneDataSet( imageCorpus , dstPath, str[ 1 ] ) ;
		}
	}
		
	public AssignSalient ( String codeBook ) throws Exception {
		Scanner bookScanner = new Scanner ( new File ( codeBook ) ) ;
		totalCenters = bookScanner.nextInt() ;
		DIM = bookScanner.nextInt() ; 
		center = new double [ totalCenters ][ DIM ] ;
		for ( int i = 0 ; i  < totalCenters ; i ++ ) 
			for ( int j = 0 ; j < DIM; j ++ ) 
				center [ i ][ j ] = bookScanner.nextDouble() ;
		bookScanner.close() ;

	}
	
	public void generateAllDataSets ( String configFile, String outputfile ) throws Exception {
			Scanner scanner = new Scanner ( new File ( configFile ));
			int datasets = scanner.nextInt () ;
			scanner.nextLine () ; 
			for ( int i = 0 ; i < datasets ; i ++ ) {
				String path = scanner.nextLine () ;
				String imageCorpus = path + "\\ImageCorpus.txt" ; 
				String dstPath = path + outputfile ;
				System.out.println ( "Generating " + dstPath ) ; 
				generateOneDataSet ( imageCorpus , dstPath, path  ) ;
			}
	}
		
	public void generateOneDataSet ( String imageCorpus , String dstPath , String env )throws Exception {
		Vector < Node > corpus = new Vector < Node > () ;
		int maxClassNo = 0 ;
		Scanner scanner = new Scanner ( new File ( imageCorpus )); 
		while ( scanner.hasNextInt () ) {
			int classNo = scanner.nextInt() ;
			int wordNo = scanner.nextInt () ;
			String path = scanner.nextLine().trim() + ".pca" ; 
			if ( path.indexOf(':')== -1 ) path = env + "\\" + path ;  
			if ( (new File(path)).exists() ) corpus.add( new Node ( classNo , wordNo, path ));
			if ( classNo > maxClassNo ) maxClassNo = classNo ; 
		}
		scanner.close() ;

		PrintStream fout = new PrintStream ( new File ( dstPath) );
		fout.println ( corpus.size() + " " + ( maxClassNo + 1 ) /2 ) ;
		for ( Node node : corpus ) {
			if ( ! (new File ( node.path ).exists() ) )continue ; 
			int [] result = generateOtherFile ( node.path ) ;
			if ( result == null ) continue ; 
			fout.print ( node.classNo + " " + node.wordNo) ;
			for ( int i = 0 ; i < totalCenters ; i ++ ) 
				if ( result [ i ] !=0 ) fout.print ( " " + (i+1) + ":" + result [ i ] );
			fout.println ( ); 
		}
		fout.close() ;
	}	
	
	private int [] generateSiftFile ( String imageFile ) throws Exception {
		int result [] = new int [ totalCenters ] ;
		Scanner scanner = new Scanner ( new File ( imageFile));
		double vec [] = new double [ DIM ] ; 
		int imageVec = scanner.nextInt() ; scanner.next() ;

		System.out.println ( imageFile );
		initSalientMap ( imageFile.replace( "sift_o", "salient" )) ;
		for ( int i = 0 ; i < imageVec ; i ++ ) {
			double row = scanner.nextDouble();
			double col = scanner.nextDouble(); 
			
			for ( int j = 0 ; j < 2 ; j ++ ) scanner.next() ;
			for ( int j = 0 ; j < DIM ; j ++ ) vec [ j ] = scanner.nextDouble() ;

			int tmp = classify ( vec ) ;
			result [ tmp ] += getVal (row, col) ;
		}
		scanner.close() ;
		return result ;	
	}

	
	private int [] generateOtherFile ( String imageFile ) throws Exception {
		int result [] = new int [ totalCenters ] ;
		Scanner scanner = new Scanner ( new File ( imageFile));
		Scanner pos = new Scanner ( new File ( imageFile.replace( "pca", "sift_o" )) ) ;
		double vec [] = new double [ DIM ] ; 
		int imageVec = scanner.nextInt() ; scanner.next() ;
		pos.nextLine(); 

		System.out.println ( imageFile );
		initSalientMap ( imageFile.replace( "pca", "salient" )) ;
		for ( int i = 0 ; i < imageVec ; i ++ ) {
			double row = pos.nextDouble();
			double col = pos.nextDouble();
			pos.nextLine();
			
			for ( int j = 0 ; j < DIM ; j ++ ) vec [ j ] = scanner.nextDouble() ;
			int tmp = classify ( vec ) ;
			result [ tmp ] += getVal (row, col) ;
		}
		scanner.close() ;
		pos.close();
		return result ;	
	}	
	
	void initSalientMap ( String filename ) throws Exception {
		Scanner scanner = new Scanner ( new File( filename )) ; 
		int oriH = scanner.nextInt() ;
		int oriW = scanner.nextInt() ; 
		int salH = scanner.nextInt() ;
		int salW = scanner.nextInt() ;
		ratioH = salH / (double) oriH ;
		ratioW = salW / (double) oriW ; 
		
		salientMap = new int [ salH ][];
		for ( int i = 0 ; i < salH ; i ++ ) {
			salientMap [ i ] = new int [ salW ];
			for ( int j = 0 ; j < salW; j ++ ) salientMap [ i ][ j ] = scanner.nextInt() ; 
		}
		scanner.close() ; 
	}
	
	int getVal ( double row, double col ) {
		row *= ratioH ;
		col *= ratioW ;
		return salientMap [(int)row][(int)col] ;
	}
	
	int classify ( double [] vec ) {
		int result = 0 ; 
		double min = Double.MAX_VALUE ;
		for ( int i = 0 ; i < totalCenters ; i ++ ) {
			double temp = euclid ( center [ i ] , vec ) ; 
			if ( temp < min ) {
				min = temp;
				result = i ; 
			}
			 
		}
		return result ; 
	}
	
	double cos_sim ( double [] v1, double [] v2 ) {   // Cosine similarity, negitive it to be distance
		int min = Math.min(v1.length, v2.length);
		double result = 0 ;
		for ( int i = 0 ; i < min ; i ++ ) result += ( v1[ i ]* v2[ i ] ) ;
		return - result ;
	}

	double euclid ( double [] v1, double [] v2 ) {   // Cosine similarity, negitive it to be distance
		int min = Math.min(v1.length, v2.length);
		double result = 0 ;
		for ( int i = 0 ; i < min ; i ++ ) result += (( v1[ i ]- v2[ i ] )*( v1[ i ]- v2[ i ] ));
		return result ;
	}	
	
	class Node {
		int classNo ;
		int wordNo ;
		String path ; 
		public Node ( int classNo , int wordNo, String path) {
			this.classNo = classNo ;
			this.wordNo = wordNo ;
			this.path = path ; 
		}
	}
}
